<template>
  <view v-if="md.done" class="birthday-picker">
    <!-- 半透明遮罩 -->
    <view :class="{ show: md.open }" :style="{ backgroundColor: maskColor }" catchtouchmove="true"
          class="mask" @click="md.open = false" @touchmove.stop.prevent>
    </view>
    <!-- 容器 -->
    <view :class="{ show: md.open }" class="wrap">
      <!-- 头部视图 -->
      <view catchtouchmove="true" class="picker-header" @touchmove.stop.prevent>
        <!-- 公历/农历切换 -->
        <view v-if="md.menus.length>1" :style="{ border: '1px solid ' + themeColor }" class="change">
          <template v-if="md.menus[0]===MENU.solar">
            <view :class="!md.isLunar ? 'active' : ''"
                  :style="!md.isLunar ? { backgroundColor: themeColor } : {}" @click="_onLunar(false)">
              公历
            </view>
            <view :class="md.isLunar ? 'active' : ''"
                  :style="md.isLunar ? { backgroundColor: themeColor } : {}" @click="_onLunar(true)">农历
            </view>
          </template>
          <template v-if="md.menus[0]===MENU.lunar">
            <view :class="md.isLunar ? 'active' : ''"
                  :style="md.isLunar ? { backgroundColor: themeColor } : {}" @click="_onLunar(true)">农历
            </view>
            <view :class="!md.isLunar ? 'active' : ''"
                  :style="!md.isLunar ? { backgroundColor: themeColor } : {}" @click="_onLunar(false)">
              公历
            </view>
          </template>
        </view>
        <view v-if="md.menus.length<=1" class="change"/>
        <!-- 标题 -->
        <text>{{ title }}</text>
        <!-- 确定按钮 -->
        <view class="submit">
          <view/>
          <text :style="{ color: themeColor }" @click="_onSubmit()">确 定</text>
        </view>
      </view>
      <!-- 公历选择器 -->
      <view v-if="!md.isLunar" class="picker-body">
        <picker-view :value="md.value" indicator-class="select-line" @change="_onChange">
          <!-- 年 -->
          <picker-view-column class="picker-view-column">
            <view v-for="(item, index) in md.cYears" :key="index" :class="
                md.selYear.num == item.num ? 'select-item' : 'column-item'
              ">
              {{ item.num }}年
            </view>
          </picker-view-column>
          <!-- 月 -->
          <picker-view-column class="picker-view-column">
            <view v-for="(item, index) in md.selYear.months" :key="index" :class="
                md.selMonth.num == item.num ? 'select-item' : 'column-item'
              ">
              {{ zeroPadding(item.num) }}月
            </view>
          </picker-view-column>
          <!-- 日 -->
          <picker-view-column class="picker-view-column">
            <view v-for="(item, index) in md.selMonth.days" :key="index" :class="
                md.selDay == item ? 'select-item' : 'column-item'
              ">
              {{ zeroPadding(item) }}日
            </view>
          </picker-view-column>
        </picker-view>

      </view>
      <!-- 农历选择器 -->
      <view v-if="md.isLunar" class="picker-body">
        <picker-view :value="md.value" indicator-class="select-line" @change="_onChange">
          <!-- 年 -->
          <picker-view-column class="picker-view-column">
            <view v-for="(item, index) in md.lYears" :key="index" :class="
			  md.selYear.num == item.num ? 'select-item' : 'column-item'
			">
              {{ item.num + item.name }}年
            </view>
          </picker-view-column>
          <!-- 月 -->
          <picker-view-column class="picker-view-column">
            <view v-for="(item, index) in md.selYear.months" :key="index" :class="
			  md.selMonth.num == item.num ? 'select-item' : 'column-item'
			">
              {{ zeroPadding(item.name) }}
            </view>
          </picker-view-column>
          <!-- 日 -->
          <picker-view-column class="picker-view-column">
            <view v-for="(item, index) in md.selMonth.days" :key="index" :class="
			  md.selDay == item ? 'select-item' : 'column-item'
			">
              {{ zeroPadding(md.selMonth.names[index]) }}
            </view>
          </picker-view-column>
        </picker-view>
      </view>
    </view>
  </view>
</template>

<script>
import calendar from 'js-calendar-converter';

export default {
  props: {
    // 显示公历、农历切换按钮（默认都显示）
    menus: {
      type: Array,
      default: () => ["solar", "lunar"],
    },
    // 选择器标题
    title: {
      type: String,
      default: "生日选择器",
    },
    // 主题色
    themeColor: {
      type: String,
      default: "#ff0000",
    },
    // 遮罩颜色
    maskColor: {
      type: String,
      default: "rgba(0, 0, 0, 0.3)",
    },
    // 起始时间（公历，不早于1901年）
    startDate: {
      type: Date,
      default: () => new Date(1901, 0, 1),
    },
    // 结束时间（公历，不晚于2100年）
    endDate: {
      type: Date,
      default: () => new Date(),
    },
    // 默认选中时间（公历）
    defaultDate: {
      type: Date,
      default: () => new Date(),
    },
    // 是否默认选中农历，默认公历（没有切换按钮时设置无效）
    defaultLunar: {
      type: Boolean,
      default: false,
    },
  },
  data() {
    return {
      MENU: {
        solar: "solar",
        lunar: "lunar",
      },
      md: {
        // 是否显示
        open: false,
        done: false,
        // 是否为农历
        isLunar: false,
        // 默认选中日期
        defaultDate: new Date(),
        // 选择器选中的索引
        value: [0, 0, 0],
        // 切换按钮
        menus: [],
        // 公历年数据[{"num":1990,"months":[{"num":1,days:[1,2]}]}]
        cYears: [],
        // 农历年数据[{"num":1990,"name":"庚子",months":[{"num":"1","name":"正月","isLeap":false,days:[1,2],names:["初一","初二"]}]}]
        lYears: [],
        // 选中的年{"num":1990,"months":[...]}
        selYear: {},
        // 选中的月{"num":1,"days":[...]}
        selMonth: {},
        // 选中的日num
        selDay: "",
      },
    };
  },
  mounted() {
    this.init();
  },
  methods: {
    init() {
      if (this.md.cYears.length == 0 && this.md.lYears.length == 0) {
        // 首次打开才赋值
        this.md.isLunar = this.defaultLunar;
        this.md.defaultDate = this.defaultDate;

        var validMenus = Object.values(this.menus);
        var menus = [];
        for (var i = 0; i < this.menus.length; i++) {
          var name = this.menus[i];
          if (validMenus.includes(name)) {
            menus.push(name);
          }
        }
        if (menus.length === 0) {
          // 都没配置的话，默认都显示
          menus.push(this.MENU.solar);
          menus.push(this.MENU.lunar);
        }
        this.md.menus = menus;
        if (menus.length === 1) {
          // 只有一个日历类型，则重新赋值isLunar
          this.md.isLunar = menus.includes(this.MENU.lunar);
        }
      }

      this.initYears();
      this.setSelectValue();
      this.md.done = true;
    },
    // 初始化年份
    initYears() {
      // 设置的开始年份、结束年份
      var startYear, endYear;
      // 选择器开始的年、月、日
      var sy, sm, sd;
      // 选择器结束的年、月、日
      var ey, em, ed;
      // 默认选中的年、月、日
      var dy, dm, dd;

      // 下面可以优化为，选中年时，先获取月列表，有则展示，无责创建；日列表同理
      if (this.md.isLunar) {
        // 农历年
        var defaultObj = calendar.solar2lunar(this.md.defaultDate.getFullYear(), this.md.defaultDate.getMonth() + 1,
            this.md
                .defaultDate.getDate());
        dy = defaultObj.lYear;
        dm = defaultObj.lMonth;
        dd = defaultObj.lDay;
        var dl = defaultObj.isLeap;

        if (this.md.lYears.length > 0) {
          // 已经创建好了
          if (this.md.open) {
            // 是切换公历/农历，需要找到已选中日期的索引
            var stop = false;
            for (var i = 0; i < this.md.lYears.length; i++) {
              var year = this.md.lYears[i];
              if (year.num === dy) {
                for (var j = 0; j < year.months.length; j++) {
                  var month = year.months[j];
                  if (month.num === dm &&
                      month.isLeap == dl) {
                    for (var k = 0; k < month.days.length; k++) {
                      if (month.days[k] === dd) {
                        this.md.value[0] = i;
                        this.md.value[1] = j;
                        this.md.value[2] = k;
                        stop = true;
                        break;
                      }
                    }
                  }
                }
                if (stop) {
                  break;
                }
              }
              if (stop) {
                break;
              }
            }
          }
          return;
        }
        // 开始日期，转农历
        var startObj = calendar.solar2lunar(this.startDate.getFullYear(), this.startDate.getMonth() + 1, this
            .startDate.getDate());
        sy = startObj.lYear;
        sm = startObj.lMonth;
        sd = startObj.lDay;
        var sl = startObj.isLeap;

        // 结束日期，转农历
        var endObj = calendar.solar2lunar(this.endDate.getFullYear(), this.endDate.getMonth() + 1, this
            .endDate.getDate());
        ey = endObj.lYear;
        em = endObj.lMonth;
        ed = endObj.lDay;
        var el = endObj.isLeap;

        startYear = Math.max(sy, 1900);
        endYear = Math.min(ey, 2099);

        const years = [];
        for (var i = startYear; i <= endYear; i++) {
          if (i === dy) {
            // 默认选中年
            this.md.value[0] = i - startYear;
          }
          // 获取本年的闰月，0为没有闰月
          var leapMonth = calendar.leapMonth(i);
          const months = [];
          for (var j = 1; j <= 12; j++) {
            if (i === dy &&
                j === dm) {
              // 默认选中月（本年无闰月||月份小于闰月||（闰月数字相同&&默认选中不是闰月））
              this.md.value[1] = j - (leapMonth <= 0 || j < leapMonth || (j === leapMonth && !dl) ? 1 : 0);
            }
            var k = 1;
            var dayCount = calendar.monthDays(i, j);
            if (i === startYear) {
              // 不能早于最小日期
              if (j < sm) {
                continue;
              } else if (j === sm) {
                k = sd;
              }
            }
            if (i === endYear) {
              // 不能晚于最大日期
              if (j > em) {
                break;
              } else if (j === em) {
                dayCount = ed;
              }
            }
            const days = [];
            const names = [];
            for (k; k <= dayCount; k++) {
              if (i === dy &&
                  j === dm &&
                  k === dd &&
                  !dl) {
                // 默认选中日（非闰月）
                this.md.value[2] = k - 1;
              }
              days.push(k);
              names.push(calendar.toChinaDay(k));
            }
            months.push({
              num: j,
              name: calendar.toChinaMonth(j),
              days: days,
              names: names,
              isLeap: false,
            });
            if (j === leapMonth) {
              // 是闰月，再添加一次
              var k = 1;
              var dayCount = calendar.leapDays(i);
              const days = [];
              const names = [];
              for (k; k <= dayCount; k++) {
                if (i === dy &&
                    j === dm &&
                    k === dd &&
                    dl) {
                  // 默认选中日（闰月）
                  this.md.value[2] = k - 1;
                }
                days.push(k);
                names.push(calendar.toChinaDay(k));
              }
              months.push({
                num: j,
                name: "闰" + calendar.toChinaMonth(j),
                days: days,
                names: names,
                isLeap: true,
              });
            }
          }
          years.push({
            num: i,
            name: calendar.toGanZhiYear(i),
            months: months,
            lunar: true, // 标识是农历数据
          });
        }
        this.md.lYears = years;
      } else {
        // 公历年
        dy = this.md.defaultDate.getFullYear();
        dm = this.md.defaultDate.getMonth() + 1;
        dd = this.md.defaultDate.getDate();

        if (this.md.cYears.length > 0) {
          // 已经创建好了
          if (this.md.open) {
            // 是切换公历/农历，需要找到已选中日期的索引
            var stop = false;
            for (var i = 0; i < this.md.cYears.length; i++) {
              var year = this.md.cYears[i];
              if (year.num === dy) {
                for (var j = 0; j < year.months.length; j++) {
                  var month = year.months[j];
                  if (month.num === dm) {
                    for (var k = 0; k < month.days.length; k++) {
                      if (month.days[k] === dd) {
                        this.md.value[0] = i;
                        this.md.value[1] = j;
                        this.md.value[2] = k;
                        stop = true;
                        break;
                      }
                    }
                  }
                }
                if (stop) {
                  break;
                }
              }
              if (stop) {
                break;
              }
            }
          }
          return;
        }

        sy = this.startDate.getFullYear();
        sm = this.startDate.getMonth() + 1;
        sd = this.startDate.getDate();

        ey = this.endDate.getFullYear();
        em = this.endDate.getMonth() + 1;
        ed = this.endDate.getDate();

        startYear = Math.max(sy, 1900);
        endYear = Math.min(ey, 2099);

        const years = [];
        for (var i = startYear; i <= endYear; i++) {
          if (i === dy) {
            // 默认选中年
            this.md.value[0] = i - startYear;
          }
          // 是闰年
          var isLeap = (i % 4) === 0;
          const months = [];
          for (var j = 1; j <= 12; j++) {
            if (i === dy &&
                j === dm) {
              // 默认选中月
              this.md.value[1] = j - 1;
            }
            var k = 1;
            var dayCount = j == 2 && isLeap ? 29 : calendar.solarDays(i, j);
            if (i === startYear) {
              // 不能早于最小日期
              if (j < sm) {
                continue;
              } else if (j === sm) {
                k = sd;
              }
            }
            if (i === endYear) {
              // 不能晚于最大日期
              var endMonth = em;
              if (j > endMonth) {
                break;
              } else if (j === endMonth) {
                dayCount = ed;
              }
            }
            const days = [];
            for (k; k <= dayCount; k++) {
              if (i === dy &&
                  j === dm &&
                  k === dd) {
                // 默认选中日
                this.md.value[2] = k - 1;
              }
              days.push(k);
            }
            months.push({
              num: j,
              days: days,
            });
          }
          years.push({
            num: i,
            months: months,
          });
        }
        this.md.cYears = years;
      }
    },
    show() {
      this.init();
      this.md.open = true;
    },
    // 隐藏选择器
    hide() {
      this.md.open = false;
    },
    _onLunar(e) {
      if (this.md.isLunar !== e) {
        this.md.isLunar = e;
        if (this.md.selYear) {
          // 将已选中的日期，转换成切换后的日历格式
          var res;
          if (this.md.isLunar) {
            // 切换成农历，那就将选中的公历转农历
            res = calendar.solar2lunar(this.md.selYear.num, this.md.selMonth.num, this.md.selDay);
          } else {
            // 切换成公历，那就将选中的农历转公历
            res = calendar.lunar2solar(this.md.selYear.num, this.md.selMonth.num, this.md.selDay, this.md.selMonth.isLeap);
          }
          this.md.defaultDate = new Date(res.cYear, res.cMonth - 1, res.cDay);
        }
        this.init();
      }
    },
    _onChange(e) {
      this.md.value = e.detail.value;
      this.setSelectValue();
    },
    setSelectValue() {
      const v = this.md.value;

      this.md.selYear = this.md.isLunar ? this.md.lYears[Math.min(v[0], this.md.lYears.length - 1)] : this.md.cYears[Math.min(v[0], this.md.cYears
          .length - 1)]
      this.md.selMonth = this.md.selYear.months[Math.min(v[1], this.md.selYear.months.length - 1)];
      this.md.selDay = this.md.selMonth.days[Math.min(v[2], this.md.selMonth.days.length - 1)];
    },
    _onSubmit() {
      var res;
      if (this.md.isLunar) {
        res = calendar.lunar2solar(this.md.selYear.num, this.md.selMonth.num, this.md.selDay, this.md.selMonth.isLeap);
      } else {
        res = calendar.solar2lunar(this.md.selYear.num, this.md.selMonth.num, this.md.selDay);
      }
      res.isLunar = this.md.isLunar;

      this.$emit("submit", res);
      this.hide();
    },
    zeroPadding(num) {
      if (this.md.isLunar) {
        return num;
      }
      return num.toString().padStart(2, "0");
    }


  },
}

</script>

<style lang="scss" scoped>
@import "./nj-birthday-picker.scss";
</style>
